package com.fz.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
@SuppressWarnings("unchecked")
public class AliOssFileUtils {
    private static Logger logger = LoggerFactory.getLogger(AliOssFileUtils.class);

    /**
     * 【oss-jxfz-image】
     * 外网：
     * * EndPoint（地域节点）： oss-cn-hangzhou.aliyuncs.com
     * * Bucket 域名： oss-jxfz-image.oss-cn-hangzhou.aliyuncs.com
     * <p>
     * 【oss-huiyun】
     * 与OSS同region的ECS 的 VPC 网络访问（内网）
     * EndPoint（地域节点）： oss-cn-shanghai-internal.aliyuncs.com
     * Bucket 域名： oss-huiyun.oss-cn-shanghai-internal.aliyuncs.com
     * 外网：
     * EndPoint（地域节点）： oss-cn-shanghai.aliyuncs.com
     * Bucket 域名： oss-huiyun.oss-cn-shanghai.aliyuncs.com
     */
    // ECS外网访问时的EndPoint（地域节点）
    private static String OUTER_ENDPOINT = PropertyUtil.getProperties("oss.OuterEndPoint");
    // ECS内网访问时的EndPoint（地域节点）
    private static String INTERNAL_ENDPOINT = PropertyUtil.getProperties("oss.InternalEndPoint");
    //阿里云API的bucket名称
    private static String BUCKET_NAME = PropertyUtil.getProperties("oss.Bucket");

    private static final String FILE_SEPARATOR = "/";

    /*
    <Schema>://<Bucket>.<Endpoint>/<Object>
    Schema：HTTP或者为HTTPS。
    Bucket：OSS存储空间名称。
    内网/外网Endpoint：Bucket所在数据中心供同地域ECS访问的内网/外网Endpoint
    Object：上传到OSS上的文件的访问路径
    */
    //阿里云API的密钥Access Key ID
    private static String ACCESS_KEY_ID = PropertyUtil.getProperties("oss.AccessKeyId");
    //阿里云API的密钥Access Key Secret
    private static String ACCESS_KEY_SECRET = PropertyUtil.getProperties("oss.AccessKeySecret");


    private static DateTimeFormatter dateFormatter = DateTimeFormatter.BASIC_ISO_DATE;
    private static DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HHmmss");

    @Autowired
    private SpringContextUtil springContextUtil;
    /**
     * 下载文件
     *
     * @param objectName
     * @return
     */
    public static File downloadFile(String objectName) {
        OSS ossClient = null;
        File file = null;
        try {
            //获取OSS客户端
            ossClient = new OSSClientBuilder().build("http://" + INTERNAL_ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            OSSObject ossObject = ossClient.getObject(BUCKET_NAME, objectName);
            String fileName;
            if (objectName.indexOf("/") > 0) {
                fileName = objectName.substring(objectName.lastIndexOf("/") + 1);
            } else {
                fileName = objectName;
            }
            logger.info("fileName = " + fileName);
            file = FileUtil.inputStreamToFile(ossObject.getObjectContent(), fileName);
            logger.info("file = " + file.getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("downloadFile异常：", e);
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return file;
    }

    /**
     * 上传File至OSS
     *
     * @param filePath   文件地址
     * @param folderName oss目录名称
     * @return objectName
     */
    public  String uploadFileToOssFolderByFilePath(String filePath, String folderName) {
        OSS ossClient = null;
        String fullFileName = "", fileName = "";
        InputStream inputStream = null;
        try {
            File file = new File(filePath);
            inputStream = new FileInputStream(file);

            //获取OSS客户端
            ossClient = new OSSClientBuilder().build("http://" + INTERNAL_ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

            logger.info("{}过滤后：{}", file.getName(), fileName);
            //防止名字冲突覆盖原有图片
            String uuid = getUUID();
            //active/文件夹名称/日期/日期+uuid
            String active = springContextUtil.getActiveProfile();
            LocalDateTime now = LocalDateTime.now();
            fullFileName = active + FILE_SEPARATOR + folderName
                    + FILE_SEPARATOR + dateFormatter.format(now)
                    + FILE_SEPARATOR + dateFormatter.format(now) + timeFormatter.format(now) + "_" + uuid + "." + FileUtil.getExtensionName(file.getName());
            logger.info("上传文件名：fileName = {}", fullFileName);

            //上传文件至OSS
            PutObjectResult putObjectResult = ossClient.putObject(BUCKET_NAME, fullFileName, inputStream);
            logger.info("uploadFileToOssFolderByFilePath eTag = {}, fileUrl = https://{}.{}/{}", putObjectResult.getETag(), BUCKET_NAME, OUTER_ENDPOINT, fullFileName);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("uploadFileToOssFolderByFilePath异常：", e);
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return fullFileName;
    }

    /**
     * 上传File至OSS
     *
     * @param filePath   文件地址
     * @param folderName oss目录名称
     * @return fileUrl oss图片url
     */
    public  String uploadOssFolderByFilePath(String filePath, String folderName) {
        String fileUrl = "";
        OSS ossClient = null;
        InputStream inputStream = null;
        try {
            File file = new File(filePath);
            inputStream = new FileInputStream(file);

            //获取OSS客户端
            ossClient = new OSSClientBuilder().build("http://" + INTERNAL_ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
            // 获取图片名字
            String fileName = file.getName();
            //防止名字冲突覆盖原有图片
            String uuid = getUUID();
            //active/文件夹名称/日期/日期+uuid
            String active = springContextUtil.getActiveProfile();
            logger.info("active = " + active);
            LocalDateTime now = LocalDateTime.now();
            fileName = active + FILE_SEPARATOR + folderName
                    + FILE_SEPARATOR + dateFormatter.format(now)
                    + FILE_SEPARATOR + dateFormatter.format(now) + timeFormatter.format(now) + "_" + uuid + "." + FileUtil.getExtensionName(fileName);
            logger.info("上传文件名：fileName = " + fileName);

            //上传文件至OSS
            PutObjectResult putObjectResult = ossClient.putObject(BUCKET_NAME, fileName, inputStream);

            fileUrl = "https://" + BUCKET_NAME + "." + OUTER_ENDPOINT + "" + FILE_SEPARATOR + fileName;

            logger.info("uploadOssFolderByFilePath eTag = {}, fileUrl = {}", putObjectResult.getETag(), fileUrl);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("uploadOssFolderByFilePath 异常：", e);
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
            // 关输入流
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return fileUrl;
    }

    /**
     * 上传MultipartFile至OSS
     *
     * @param multipartFile
     * @param folderName    oss目录名称MultipartUpload
     * @return
     */
    public  Map<String, Object> uploadMultipartFileToOssFolder(MultipartFile multipartFile, String folderName) {
        Map<String, Object> resultMap = new HashMap<>();
        String eTag = "";
        String fileUrl = "";
        OSS ossClient = null;
        InputStream inputStream = null;
        try {
            //获取OSS客户端
            ossClient = new OSSClientBuilder().build("http://" + INTERNAL_ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
            String fileName = multipartFile.getOriginalFilename();
            //active/文件夹名称/日期/日期+uuid
            String active = springContextUtil.getActiveProfile();
            logger.info("active = " + active);
            LocalDateTime now = LocalDateTime.now();
            fileName = active + FILE_SEPARATOR + folderName
                    + FILE_SEPARATOR + dateFormatter.format(now)
                    + FILE_SEPARATOR + dateFormatter.format(now) + timeFormatter.format(now) + "_" + getUUID() + "." + FileUtil.getExtensionName(fileName); // UUID防止名字冲突覆盖原有图片
            logger.info("上传文件名：fileName = " + fileName);

            inputStream = multipartFile.getInputStream();
            //上传文件至OSS
            PutObjectResult putObjectResult = ossClient.putObject(BUCKET_NAME, fileName, inputStream);
            eTag = putObjectResult.getETag();
            fileUrl = "https://" + BUCKET_NAME + "." + OUTER_ENDPOINT + "" + FILE_SEPARATOR + fileName;

            logger.info("uploadMultipartFileToOssFolder eTag = {}, fileUrl = {}", eTag, fileUrl);

            resultMap.put("objectName", fileName);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("uploadMultipartFileToOssFolder 异常：", e);
            resultMap.put("errorMsg", e.getMessage());
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
            // 关输入流
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        resultMap.put("eTag", eTag);
        resultMap.put("fileUrl", fileUrl);

        return resultMap;
    }

    /**
     * 上传MultipartFile至OSS
     *
     * @param multipartFile
     * @return
     */
    public static Map<String, Object> uploadMultipartFile(MultipartFile multipartFile) {
        Map<String, Object> resultMap = new HashMap<>();
        String eTag = "";
        String fileUrl = "";
        OSS ossClient = null;
        InputStream inputStream = null;
        try {
            //获取OSS客户端
            ossClient = new OSSClientBuilder().build("http://" + INTERNAL_ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
            // 获取图片名字
            String fileName = multipartFile.getOriginalFilename();

            LocalDateTime now = LocalDateTime.now();
            //防止名字冲突覆盖原有图片
            String uuid = getUUID();
            fileName = dateFormatter.format(now) + timeFormatter.format(now) + "_" + uuid + "." + FileUtil.getExtensionName(fileName);
            logger.info("fileName = " + fileName);

            inputStream = multipartFile.getInputStream();
            //上传文件至OSS
            PutObjectResult putObjectResult = ossClient.putObject(BUCKET_NAME, fileName, inputStream);

            fileUrl = "https://" + BUCKET_NAME + "." + OUTER_ENDPOINT + "" + FILE_SEPARATOR + fileName;

            logger.info("uploadMultipartFile eTag = {}, fileUrl = {}", putObjectResult.getETag(), fileUrl);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("uploadMultipartFile 异常：", e);
            resultMap.put("errorMsg", e.getMessage());
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
            // 关输入流
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        resultMap.put("eTag", eTag);
        resultMap.put("fileUrl", fileUrl);

        return resultMap;
    }

    /**
     * 文件以二进制数组上传至OSS
     *
     * @param bytes      文件二进制数组
     * @param folderName 分类文件夹
     * @param type       文件类型
     * @return
     */
    public  Map<String, Object> uploadBytesToOssFolder(byte[] bytes, String folderName, String type) {
        Map<String, Object> resultMap = new HashMap<>();
        String eTag = "";
        String fileUrl = "";
        OSS ossClient = null;
        InputStream inputStream = null;
        try {
            //获取OSS客户端
            ossClient = new OSSClientBuilder().build("http://" + INTERNAL_ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

            String uuid = getUUID();
            //active/文件夹名称/日期/日期+uuid
            String active = springContextUtil.getActiveProfile();
            logger.info("active = " + active);
            LocalDateTime now = LocalDateTime.now();
            String fileName = active + FILE_SEPARATOR + folderName +
                    FILE_SEPARATOR + dateFormatter.format(now) +
                    FILE_SEPARATOR + dateFormatter.format(now) + timeFormatter.format(now) + "_" + uuid + "." + type;
            logger.info("上传文件名：fileName = " + fileName);

            //上传文件至OSS
            inputStream = new ByteArrayInputStream(bytes);
            PutObjectResult putObjectResult = ossClient.putObject(BUCKET_NAME, fileName, inputStream);
            eTag = putObjectResult.getETag();
            fileUrl = "https://" + BUCKET_NAME + "." + OUTER_ENDPOINT + "" + FILE_SEPARATOR + fileName;

            logger.info("uploadBytesToOssFolder eTag = {}, fileUrl = {}", eTag, fileUrl);

            resultMap.put("objectName", fileName);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("uploadBytesToOssFolder 异常：", e);
            resultMap.put("errorMsg", e.getMessage());
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
            // 关输入流
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        resultMap.put("eTag", eTag);
        resultMap.put("fileUrl", fileUrl);

        return resultMap;
    }

    /**
     * 判断字符串中是否包含中文
     *
     * @param str 待校验字符串
     * @return 是否为中文
     * @warn 不能校验是否为中文标点符号
     */
    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);

        return m.find();
    }

    /**
     * 过滤掉中文
     *
     * @param str 待过滤中文的字符串
     * @return 过滤掉中文后字符串
     */
    public static String filterChinese(String str) {
        // 用于返回结果
        String result;
        if (isContainChinese(str)) { // 包含中文
            // 用于拼接过滤中文后的字符
            StringBuffer sb = new StringBuffer();
            // 用于临时存储单字符
            char chinese = 0;
            // 5.去除掉文件名中的中文
            // 将字符串转换成char[]
            char[] charArray = str.toCharArray();
            // 过滤到中文及中文字符
            for (int i = 0; i < charArray.length; i++) {
                chinese = charArray[i];
                if (!isChinese(chinese)) { // 不是中日韩文字及标点符号
                    sb.append(chinese);
                }
            }
            result = sb.toString();
        } else {
            return str;
        }
        return result;
    }

    /**
     * 判定输入的是否是汉字
     *
     * @param c 被校验的字符
     * @return true代表是汉字
     */
    public static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
            return true;
        }
        return false;
    }

    /**
     * 生成OSS文件UUID名称
     *
     * @return
     */
    public static String getUUID() {
        return UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }


}
